package cn.wss.flowable.service.impl;

import cn.wss.flowable.common.Page;
import cn.wss.flowable.common.Params;
import cn.wss.flowable.model.FlowableDeployment;
import cn.wss.flowable.model.FlowableProcessDefinition;
import cn.wss.flowable.service.Conditions;
import cn.wss.flowable.service.FlowableRepositoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.repository.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class FlowableRepositoryServiceImpl implements FlowableRepositoryService, Conditions {

    private Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private RepositoryService repositoryService;

    /**
     * @Description 通过文件路径部署流程图
     * @Param path 文件路径
     * @Param variables 参数
     * @Return 部署信息
     */
    @Override
    public FlowableDeployment deployByFile(String path, Map<String, Object> variables) throws Exception {
        File file = new File(path);
        String fileName = file.getName();
        if (!fileName.endsWith("bpmn20.xml") && !fileName.endsWith("bpmn")) {
            throw new RuntimeException("文件名错误,需以\"bpmn20.xml\"或者\"bpmn\"结尾");
        }

        FileInputStream inputStream = new FileInputStream(file);
        Deployment deployment = null;
        try {
            deployment = getDeploymentBuilder(variables).addInputStream(fileName, inputStream).deploy();
        } catch (Exception e) {
            logger.error("部署失败:", e.getMessage());
        } finally {
            inputStream.close();
        }
        return transformDeployment(deployment);
    }

    /**
     * @Description 通过字符串部署流程图
     * @Param name 文件名称
     * @Param data xml文件内容
     * @Param variables 参数
     * @Return 部署信息
     */
    @Override
    public FlowableDeployment deployByString(String name, String data, Map<String, Object> variables) {
        if (!name.endsWith("bpmn20.xml") && !name.endsWith("bpmn")) {
            throw new RuntimeException("文件名错误,需以bpmn20.xml或者bpmn结尾");
        }
        return transformDeployment(getDeploymentBuilder(variables).addString(name, data).deploy());
    }

    /**
     * @Description 通过部署id删除部署信息
     * @Param id 部署id
     */
    @Override
    public void deleteDeploymentById(String id) {
        repositoryService.deleteDeployment(id);
    }

    /**
     * @Description 分页查询部署信息(默认0,10)
     * @Param variables 参数
     * @Return 部署信息
     */
    @Override
    public Page<FlowableDeployment> pageDeployment(Map<String, Object> variables) {
        Page<FlowableDeployment> page = new Page(variables);
        Params params = new Params(variables);
        DeploymentQuery query = repositoryService.createDeploymentQuery().orderByDeploymentTime().desc();

        if (params.containsKey(ID)) {
            query.deploymentId(params.get(ID));
        }
        if (params.containsKey(KEY)) {
            query.deploymentKey(params.get(KEY));
        }
        if (params.containsKey(NAME)) {
            query.deploymentName(params.get(NAME));
        }
        if (params.containsKey(NAME_LIKE)) {
            query.deploymentNameLike("%" + params.get(NAME_LIKE) + "%");
        }
        if (params.containsKey(TENANT_ID)) {
            query.deploymentTenantId(params.get(TENANT_ID));
        }
        if (params.containsKey(PROCESS_DEFINITION_KEY)) {
            query.processDefinitionKey(params.get(PROCESS_DEFINITION_KEY));
        }

        int totalElements = query.list().size();
        List<Deployment> list = query.listPage((page.getPageNum() - 1) * page.getPageSize(), page.getPageSize());
        List<FlowableDeployment> deployments = new ArrayList<>();

        list.forEach(s -> {
            deployments.add(new FlowableDeployment(s));
        });
        page.setData(deployments);
        page.setTotalElements(totalElements);
        return page;
    }

    /**
     * @Description 分页查询流程定义(默认0,10)
     * @Param variables 参数
     * @Return 流程定义信息
     */
    @Override
    public Page<FlowableProcessDefinition> pageProcessDefinition(Map<String, Object> variables) {
        Page<FlowableProcessDefinition> page = new Page(variables);
        Params params = new Params(variables);
        ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery().latestVersion().orderByProcessDefinitionId().desc();

        if (params.containsKey(ID)) {
            query.processDefinitionId(params.get(ID));
        }
        if (params.containsKey(IDS)) {
            query.processDefinitionIds((params.getSet(IDS)));
        }
        if (params.containsKey(KEY)) {
            query.processDefinitionKey(params.get(KEY));
        }
        if (params.containsKey(NAME)) {
            query.processDefinitionName(params.get(NAME));
        }
        if (params.containsKey(NAME_LIKE)) {
            query.processDefinitionNameLike("%" + params.get(NAME_LIKE) + "%");
        }
        if (params.containsKey(TENANT_ID)) {
            query.processDefinitionTenantId(params.get(TENANT_ID));
        }
        if (params.containsKey(DEPLOYMENT_ID)) {
            query.deploymentId(params.get(DEPLOYMENT_ID));
        }

        int totalElements = query.list().size();
        List<ProcessDefinition> list = query.listPage((page.getPageNum() - 1) * page.getPageSize(), page.getPageSize());
        List<FlowableProcessDefinition> definitions = new ArrayList<>();

        list.forEach(s -> {
            definitions.add(new FlowableProcessDefinition(s));
        });

        page.setData(definitions);
        page.setTotalElements(totalElements);
        return page;
    }

    private DeploymentBuilder getDeploymentBuilder(Map<String, Object> variables) {
        DeploymentBuilder builder = repositoryService.createDeployment();
        Params params = new Params(variables);

        if (params.containsKey(KEY)) {
            builder.key(params.get(KEY));
        }
        if (params.containsKey(NAME)) {
            builder.name(params.get(NAME));
        }
        if (params.containsKey(TENANT_ID)) {
            builder.tenantId(params.get(TENANT_ID));
        }
        return builder;
    }

    private FlowableDeployment transformDeployment(Deployment deployment) {
        FlowableDeployment flowableDeployment = new FlowableDeployment();
        BeanUtils.copyProperties(deployment, flowableDeployment);
        return flowableDeployment;
    }
}
